﻿namespace System.ServiceModel.DomainServices.Client
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.Linq;
    using System.ComponentModel.DataAnnotations;

    public abstract class LoadOperation : OperationBase
    {
        private ReadOnlyObservableCollection<Entity> _allEntities;
        private ObservableCollection<Entity> _allEntitiesCollection;
        private ReadOnlyObservableCollection<Entity> _entities;
        private ObservableCollection<Entity> _entitiesCollection;
        private System.ServiceModel.DomainServices.Client.LoadBehavior _loadBehavior;
        private System.ServiceModel.DomainServices.Client.EntityQuery _query;
        private IEnumerable<ValidationResult> _validationErrors;

        internal LoadOperation(System.ServiceModel.DomainServices.Client.EntityQuery query, System.ServiceModel.DomainServices.Client.LoadBehavior loadBehavior, object userState) : base(userState)
        {
            this._entitiesCollection = new ObservableCollection<Entity>();
            this._allEntitiesCollection = new ObservableCollection<Entity>();
            if (query == null)
            {
                throw new ArgumentNullException("query");
            }
            this._query = query;
            this._loadBehavior = loadBehavior;
        }

        internal void Complete(IEnumerable<ValidationResult> validationErrors)
        {
            this._validationErrors = validationErrors;
            base.RaisePropertyChanged("ValidationErrors");
            DomainOperationException exception = new DomainOperationException(string.Format(CultureInfo.CurrentCulture, Resource.DomainContext_LoadOperationFailed_Validation, new object[] { this.EntityQuery.QueryName }), OperationErrorStatus.ValidationFailed);
            base.Complete((Exception) exception);
        }

        internal void Complete(Exception error)
        {
            if (typeof(DomainException).IsAssignableFrom(error.GetType()))
            {
                base.Complete(error);
            }
            else
            {
                string message = string.Format(CultureInfo.CurrentCulture, Resource.DomainContext_LoadOperationFailed, new object[] { this.EntityQuery.QueryName, error.Message });
                DomainOperationException exception = error as DomainOperationException;
                if (exception != null)
                {
                    error = new DomainOperationException(message, exception);
                }
                else
                {
                    error = new DomainOperationException(message, error);
                }
                base.Complete(error);
            }
        }

        internal void Complete(DomainClientResult result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }
            if (result.Entities.Any<Entity>())
            {
                this.UpdateResults(result);
            }
            base.Complete(result);
            if (result.Entities.Any<Entity>())
            {
                base.RaisePropertyChanged("TotalEntityCount");
            }
        }

        internal static LoadOperation Create<TEntity>(EntityQuery<TEntity> query, System.ServiceModel.DomainServices.Client.LoadBehavior loadBehavior, Action<LoadOperation> completeAction, object userState, Action<LoadOperation> cancelAction) where TEntity: Entity
        {
            Action<LoadOperation<TEntity>> action3 = null;
            Action<LoadOperation<TEntity>> action4 = null;
            Action<LoadOperation<TEntity>> action = null;
            Action<LoadOperation<TEntity>> action2 = null;
            if (completeAction != null)
            {
                if (action3 == null)
                {
                    action3 = delegate (LoadOperation<TEntity> arg) {
                        completeAction(arg);
                    };
                }
                action = action3;
            }
            if (cancelAction != null)
            {
                if (action4 == null)
                {
                    action4 = delegate (LoadOperation<TEntity> arg) {
                        cancelAction(arg);
                    };
                }
                action2 = action4;
            }
            return new LoadOperation<TEntity>(query, loadBehavior, action, userState, action2);
        }

        protected virtual void UpdateResults(DomainClientResult result)
        {
            if (result == null)
            {
                throw new ArgumentNullException("result");
            }
            if (this._entities != null)
            {
                this._entitiesCollection.Clear();
                foreach (Entity entity in result.Entities)
                {
                    this._entitiesCollection.Add(entity);
                }
            }
            if (this._allEntities != null)
            {
                this._allEntitiesCollection.Clear();
                foreach (Entity entity2 in result.AllEntities)
                {
                    this._allEntitiesCollection.Add(entity2);
                }
            }
        }

        public IEnumerable<Entity> AllEntities
        {
            get
            {
                if (this._allEntities == null)
                {
                    if ((this.Result != null) && this.Result.AllEntities.Any<Entity>())
                    {
                        foreach (Entity entity in this.Result.AllEntities)
                        {
                            this._allEntitiesCollection.Add(entity);
                        }
                    }
                    this._allEntities = new ReadOnlyObservableCollection<Entity>(this._allEntitiesCollection);
                }
                return this._allEntities;
            }
        }

        public IEnumerable<Entity> Entities
        {
            get
            {
                if (this._entities == null)
                {
                    if ((this.Result != null) && this.Result.Entities.Any<Entity>())
                    {
                        foreach (Entity entity in this.Result.Entities)
                        {
                            this._entitiesCollection.Add(entity);
                        }
                    }
                    this._entities = new ReadOnlyObservableCollection<Entity>(this._entitiesCollection);
                }
                return this._entities;
            }
        }

        public System.ServiceModel.DomainServices.Client.EntityQuery EntityQuery
        {
            get
            {
                return this._query;
            }
        }

        public System.ServiceModel.DomainServices.Client.LoadBehavior LoadBehavior
        {
            get
            {
                return this._loadBehavior;
            }
        }

        protected DomainClientResult Result
        {
            get
            {
                return (DomainClientResult) base.Result;
            }
        }

        public int TotalEntityCount
        {
            get
            {
                if (this.Result != null)
                {
                    return this.Result.TotalEntityCount;
                }
                return 0;
            }
        }

        public IEnumerable<ValidationResult> ValidationErrors
        {
            get
            {
                if (this.Result != null)
                {
                    return this.Result.ValidationErrors;
                }
                if (this._validationErrors == null)
                {
                    this._validationErrors = new ValidationResult[0];
                }
                return this._validationErrors;
            }
        }
    }
}

